--[[
    中心计时器模块 v1.1
        v1.2 计划
            >再添加 1 秒中心计时器 将>=1秒的计时器丢入 减轻负担
                >问题:流逝时间无法精确到0.01级别
                    >解决方案:引入一个新的值 cs (centisecond)厘秒
    创建：雪月灬雪歌    2022/01/25
    修改：雪月灬雪歌    2022/01/26
]]

local CreateTimer = cj.CreateTimer
local TimerStart  = cj.TimerStart
---@class mTimer  Timer类
local mTimer = {
    type = 'class',
    __id = 0,
    --计时器计数器，不可靠，没使用del销毁的不会减少计数器
    count = 0,
    --队列
    __queue = {
            [0] = 0,
    },
    --当前循环周期 无限增加数 每过0.01秒 增加1
    cur = 0,
}
---@class cTimer
local cTimer = {

--计时器默认值

    -- 周期数 用来记录当前计时器时间 一个周期 等于 中心计时器 的基本时间
    cycle = 0,
    maxcycle = 0,

    --回调函数
    callback = nil,

    --间歇 循环型计时器
    interval = false,

    --暂停 通过赋值计时器的pause = true 可以达到暂停计时器
    pause = false,

    --销毁 再下个周期时才会被销毁 可直接赋值true来销毁
    destroy = false,

    --在队列中
    inqueue = false
}

---@return number 类似于os.clock 精度0.01
function mTimer:clock()
    return self.cur * 0.01
end

--新建计时器
---@return timer
function mTimer:new()
    mTimer.__id = mTimer.__id + 1
    mTimer.count = mTimer.count + 1
    ---@class timer : cTimer 计时器对象
    local t = setmetatable(
        {
            type = 'timer',
            --ID
            id = mTimer.__id,
        },
        {
            __index = cTimer
        }
    )
    return t
end


--启动计时器[如果没新建计时器系统会自动新建一个并返回]
--@param interval boolean 是否周期执行
--@param time number 时间 秒计算
--@param callback function 计时器回调函数
--@return timer
function mTimer:timer( interval, time, callback )
    if type(time) ~='number' or type(callback) ~= 'function' then
        return nil
    end
    local cycle = time * 100
    self = self:new()
    self.cycle = 0
    self.maxcycle = cycle
    self.interval = interval
    self.pause = false
    self.destroy = false
    self.callback = callback
    if not self.inqueue then --不在队列中 加入队列
        self.inqueue = true
        mTimer.__queue[0] = mTimer.__queue[0] + 1
        mTimer.__queue[mTimer.__queue[0]] = self
    end
    return self
end

--- self:module
--- 启动计时器[一次][如果没新建计时器系统会自动新建一个并返回]
---@param time number 时间 按秒计算
---@param callback fun(t:timer) 计时器回调函数
---@return timer
function mTimer:once(time, callback)
    ---@type timer
    local t = self:timer(false, time, callback)
    return t
end

--- self:module
--- 启动计时器[循环][如果没新建计时器系统会自动新建一个并返回]
---@param time number 时间 按秒计算
---@param callback fun(t:timer) 计时器回调函数
---@return timer
function mTimer:loop(time,callback)
    ---@type timer
    local t = self:timer(true, time, callback)
    return t
end

--- self:module
--- 启动计时器[循环指定次数][如果没新建计时器系统会自动新建一个并返回]
---@param time number 时间 按秒计算
---@param times int 循环的次数
---@param callback fun(t:timer,i:int) 计时器回调函数
---@return timer
function mTimer:times(time, times, callback)
    local i = 0
    ---@type timer
    local t = self:timer(true, time, function (t)
        i = i + 1
        if i <= times then
            callback( t, i )
        else
            t.pause = true
            --t:del()
        end
    end)
    return t
end

--self: timer
--销毁计时器
function cTimer:del()
    self.destroy = true
    setmetatable(self, nil)
    mTimer.count = mTimer.count - 1
end
--self:timer
--计时器剩余时间
function cTimer:remain()
    local cycle = self.maxcycle - self.cycle
    return math.max( 0, cycle / 100 )
end
--self:timer
--计时器已流逝时间
function cTimer:elapsed()
    local cycle = self.cycle
    return math.max( 0, cycle / 100 )
end
--self:timer
--计时器到期时间
function cTimer:timeout( )
    local cycle = self.maxcycle
    return math.max( 0, cycle / 100 )
end

--self:timer
--重置计时器
function cTimer:reset(pause)
    self.cycle = 0
    if pause then
        self.pause = pause
    end
end


local __queue = mTimer.__queue

--@private
--中心计时器
local function timer_callback()
    local i,max_i = 1,__queue[0]
    local offset,t = 0 --引入偏移值offset 去掉table.remove 优化效率 2022/01/26 21:32 雪歌
    mTimer.cur = mTimer.cur + 1
    while i <= max_i do
        ----偏移值处理：删除有序表的值 同时使后面的值自动补前
            if offset > 0 then
                    --存在偏移值:将后面的队列前移
                    t = __queue[ i ]
                    __queue[ i ] = nil
                    __queue[i - offset] = t
            else
                    t = __queue[ i ]
            end
        ----中心计时器处理
            if t.destroy then --标记销毁
                offset = offset + 1 --须知：如果当前是最后一次循环的话该元素将无法回到开始部分的偏移值处理部分set nil
            elseif t.pause then --暂停
                offset = offset + 1
            else
                t.cycle = t.cycle + 1
                if t.cycle >= t.maxcycle then
                    local status, sErr = xpcall(t.callback, debug.traceback, t)
                    t.cycle = 0 --计时清零
                    if status then
                        if not t.interval then
                                offset = offset + 1
                        end
                    else
                        print(sErr)
                    end
                end
            end
            i = i + 1
    end
    __queue[0] = max_i - offset --数组大小记录
end

TimerStart(CreateTimer(), 0.01, true, timer_callback)
return mTimer